package org.springblade.metadata.service.impl;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.metadata.config.FTPProperties;
import org.springblade.metadata.model.DataSource;
import org.springblade.metadata.model.FTPTree;
import org.springblade.metadata.service.FTPFileWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@Component
public class FTPFileWriterImpl implements FTPFileWriter {

    private static final Logger logger = LoggerFactory.getLogger(FTPFileWriterImpl.class);
    private FTPProperties FTPProperties;
    protected FTPClient ftpClient;

    @Autowired
    public FTPFileWriterImpl(@Autowired FTPProperties FTPProperties) {
        this.FTPProperties = FTPProperties;
    }

    /*@PostConstruct
    public void init() {
        if (this.FTPProperties.isAutoStart()) {
            logger.debug("Autostarting connection to FTP server.");
            this.open();
        }
    }*/

    public boolean open(DataSource dataSource) {
        close();
        logger.info("Connecting and logging in to FTP server.");
        ftpClient = new FTPClient();
        boolean loggedIn = false;
        try {
            ftpClient.connect(dataSource.getHost(), Integer.parseInt(dataSource.getPort()));
            loggedIn = ftpClient.login(dataSource.getUserName(), dataSource.getPassword());
			logger.info("host="+dataSource.getHost()+" port="+dataSource.getPort()+" loggedIn="+loggedIn);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return loggedIn;
    }

    public void close() {
        if (ftpClient != null) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (Exception e) {
                //logger.error(e.getMessage(), e);
            }
        }
    }

    public boolean loadFile(String remotePath, OutputStream outputStream) {
        try {
            logger.debug("Trying to retrieve a file from remote path " + remotePath);
            return ftpClient.retrieveFile(remotePath, outputStream);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    public boolean saveFile(InputStream inputStream, String destPath, boolean append) {
        try {
            logger.debug("Trying to store a file to destination path " + destPath);
            if(append)
                return ftpClient.appendFile(destPath, inputStream);
            else
                return ftpClient.storeFile(destPath, inputStream);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

    public boolean saveFile(String sourcePath, String destPath, boolean append) {
        InputStream inputStream = null;
        try {
            inputStream = new ClassPathResource(sourcePath).getInputStream();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return false;
        }
        return this.saveFile(inputStream, destPath, append);
    }

	public FTPFile[] listFiles(DataSource dataSource,String destPath) {
		try {
			logger.info("Trying to store a file to destination path " + destPath);
			this.open(dataSource);
			ftpClient.enterLocalPassiveMode();
			return ftpClient.listFiles(destPath);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	public FTPFile[] listDirectories(DataSource dataSource,String destPath) {
		try {
			logger.debug("Trying to store a file to destination path " + destPath);
			this.open(dataSource);
			ftpClient.enterLocalPassiveMode();
			return ftpClient.listDirectories(destPath);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	public FTPTree recursionDir(DataSource dataSource,String destPath){
		try {
			this.open(dataSource);
			if (ftpClient.getReplyCode() > 0) {
				String directory = destPath;
				ftpClient.changeWorkingDirectory(directory);
				ftpClient.enterLocalPassiveMode();
				FTPFile[] ftpFiles = ftpClient.listFiles();
				FTPTree root = new FTPTree(directory);
				if (ftpFiles.length > 0) {
					this.recursion(ftpFiles, ftpClient, root,false);
				}
				this.close();
				return root;
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	private FTPTree recursion(FTPFile[] fileArr, FTPClient ftp, FTPTree ftpTree,boolean hasFile) throws Exception {
		if (fileArr.length > 0) {
			for (FTPFile it : fileArr) {
				if (it.isDirectory()) {
					ftp.changeWorkingDirectory(new String(it.getName().getBytes("utf-8"), "iso-8859-1"));
					FTPFile[] ftpFiles = ftp.listFiles();
					if (ftpFiles.length > 0) {
						ftpTree.getChildren().add(this.recursion(ftpFiles, ftp, new FTPTree(it.getName()),hasFile));
					} else {
						ftpTree.getChildren().add(new FTPTree(it.getName()));
						ftp.changeToParentDirectory();  // 空目录务必要返回上一级
					}
				} else {
					if (hasFile){
						ftpTree.getChildren().add(new FTPTree(it.getName()));
					}
				}
			}
		}
		ftp.changeToParentDirectory();
		return ftpTree;
	}

	public FTPTree recursionDirFile(DataSource dataSource,String destPath){
		try {
			this.open(dataSource);
			if (ftpClient.getReplyCode() > 0) {
				String directory = destPath;
				ftpClient.changeWorkingDirectory(directory);
				ftpClient.enterLocalPassiveMode();
				FTPFile[] ftpFiles = ftpClient.listFiles();
				FTPTree root = new FTPTree(directory);
				if (ftpFiles.length > 0) {
					this.recursion(ftpFiles, ftpClient, root,true);
				}
				this.close();
				return root;
			} else {
				return null;
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

    public boolean isConnected() {
        boolean connected = false;
        if (ftpClient != null) {
            try {
                connected = ftpClient.sendNoOp();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        logger.debug("Checking for connection to FTP server. Is connected: " + connected);
        return connected;
    }
}
